<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- <button>点击</button> -->
    <script>
        /* 创建类并添加属性和方法 */
        // class Stars {
        //     constructor(name, age, sex) {
        //         this.name = name;
        //         this.age = age;
        //         this.sex = sex;
        //     }
        //     sing(song) {
        //         console.log(this.name + song);
        //     }
        // }
        // let zs = new Stars('张三', 18, '男');
        // console.log(zs);
        // zs.sing('法外狂徒')


        /* 类的继承 */
        // class Father {
        //     constructor(surname) {
        //         this.surname = '王';
        //     }
        //     money() {
        //         console.log('家产100元');
        //     }
        // }
        // class Son extends Father {

        // }
        // // console.log(Sun);
        // let son = new Son();
        // console.log(son.surname);
        // son.money()


        /* super关键字 */
        // class Father {
        //     constructor(x, y) {
        //         this.x = x;
        //         this.y = y;
        //     }
        //     getSum() {
        //         console.log(this.x + this.y);
        //     }
        // }
        // class Son extends Father {
        //     constructor(x, y) {
        //         super(x, y) //调用父类中的构造函数
        //     }
        // }
        // const son = new Son(1, 2);
        // son.getSum();

        // class Father {
        //     say() {
        //         return '我是你爹';
        //     }
        // }
        // class Son extends Father {
        //     say() {
        //         console.log(super.say());
        //     }
        // }
        // const son = new Son();
        // son.say()

        // class Father {
        //     constructor(x, y) {
        //         this.x = x;
        //         this.y = y;
        //     }
        //     sum() {
        //         console.log(this.x + this.y);
        //     }
        // }
        // class Son extends Father {
        //     constructor(x, y) {
        //         super(x, y)
        //         this.x = x;
        //         this.y = y;
        //     }
        //     sub() {
        //         console.log(this.x - this.y);
        //     }
        // }
        // const son = new Son(2, 1);
        // son.sum();
        // son.sub();


        /* this指向 */
        // var that;
        // class Star {
        //     constructor(name, age) {
        //         that = this;
        //         // console.log(this);
        //         this.name = name;
        //         this.age = age;
        //         // this.sing();
        //         this.btn = document.querySelector('button');
        //         this.btn.onclick = this.sing;
        //     }
        //     sing() {
        //         // console.log(this);
        //         console.log(that.name);
        //     }
        // }
        // const star = new Star('张三', 18);
        // // console.log(star);


        /* 构造函数创建函数 */
        // const fn = new Function('console.log(\'卢本伟\')')
        // fn()
        // const fn = new Function('a', 'b', 'console.log(a+b)')
        // fn(1, 3);
        // console.dir(fn);
        // console.log(fn instanceof Object);


        /* 实例成员和静态成员 */
        // function Star(name, age) {
        //     this.name = name; //构造函数内部由this构建的，name age 是实例成员
        //     this.age = age;
        //     Star.sex = '男' //构造函数本身的成员，sex是静态成员
        // }
        // const ldh = new Star('刘德华', 18);
        // Star.nikename = '伞兵一号'
        // console.log(ldh.name); //实例成员只能由实例化的对象来访问
        // console.log(Star.sex); //静态成员只有构造函数本身才能访问
        // console.log(Star.nikename);
        // console.log(ldh.sex);


        /* 构造函数和原型 */
        // function Star(name, age) {
        //     this.name = name;
        //     this.age = age;
        //     // this.sing = function() {
        //     //     console.log('我会唱歌');
        //     // }
        // }
        // // Star.prototype.sing = function() {
        // //     console.log('我会唱歌');
        // // }
        // Star.prototype = {
        //     constructor: Star, //令prototype为一个对象，则prototype会被覆盖掉，从而丢失constructor属性，需要手动添加
        //     sing: function() {
        //         console.log('唱歌');
        //     },
        //     movie: function() {
        //         console.log('电影');
        //     }
        // }
        // const ldh = new Star('刘德华', 18)
        // const zxy = new Star('张学友', 19)
        // console.log(ldh.sing === zxy.sing); //方法相同但存放的地址不同，返回false
        // ldh.sing()
        // console.log(Star.prototype);
        // console.log(ldh.__proto__);
        // console.log(Star.prototype.constructor);
        // console.log(ldh.__proto__.constructor);


        /* 原型链 */
        // function Star(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }
        // Star.prototype.sing = function() {
        //     console.log('唱歌');
        // }
        // const ldh = new Star('刘德华', 18)
        // console.log(Star.prototype);
        // console.log(Star.prototype.__proto__ === Object.prototype);
        // console.log(Object.prototype.constructor === Object);


        /* 原型对象this问题 */
        // function Star(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }
        // var that;
        // Star.prototype.sing = function() {
        //     console.log('唱歌');
        //     that = this;
        // }
        // const ldh = new Star('刘德华', 18)
        // ldh.sing()
        // console.log(that === ldh);


        /* 扩展内置对象 */
        // console.log(Array.prototype);
        // Array.prototype.sum = function() {
        //     var sum = 0;
        //     for (let i = 0; i < this.length; i++) {
        //         sum = sum + this[i]
        //     }
        //     return sum
        // }
        // const arr = [1, 2, 3]
        // console.log(arr.sum());
        // var arr1 = new Array(11, 22, 33)
        // console.log(arr1.sum());


        /* call方法测试 */
        // function fn(x, y) {
        //     console.log('伞兵一号卢本伟准备就绪');
        //     console.log(this);
        //     console.log(x + y);
        // }
        // const o = {
        //     name: '卢本伟'
        // }
        // fn.call() //call()可以调用函数
        // fn.call(o) //可以改变this的指向，此时这个函数就指向了o这个对象。
        // fn.call(o, 1, 2)


        /* 利用构造函数继承父类的属性 */
        //1.父构造函数
        // function Father(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }
        // Father.prototype.money = function() {
        //         console.log('挣钱');
        //     }
        //     //2.子构造函数
        // function Son(name, age) {

        //     Father.call(this, name, age)
        // }
        // Son.prototype = new Father();
        // const ldh = new Son('刘德华', 18) //Son.prototype被Father的实例对象覆盖了，需要重新指定constructor
        // Son.prototype.constructor = Son;
        // console.log(ldh);
        // console.log(ldh.money());
        // console.log(Son.prototype.constructor);


        /* 类的本质 */
        // class Star {

        // }
        // Star.prototype.sing = function() {
        //     console.log('伞兵一号');
        // }
        // const ldh = new Star();
        // ldh.sing()
        // console.log(Star.prototype);
        // console.log(Star.prototype.constructor);
        // console.dir(ldh)
        // console.log(ldh.__proto__ === Star.prototype);


        /*ES5新增方法-数组方法 */
        // forEach 迭代数组 在forEach里面写return不会终止迭代
        // const arr = [1, 2, 3];
        // var sum = 0
        // arr.forEach(function(value, index, array) {
        //     console.log('数组元素' + value);
        //     console.log('数组索引号' + index);
        //     console.log('数组本身' + array);
        //     sum += value
        // })
        // console.log(sum);

        // filter 筛选所有符合条件的元素 在filter里面写return不会终止迭代
        // const arr = [1, 3, 11, 32, 43]
        // let newArr = arr.filter(function(value, index) {
        //     // return value >= 10
        //     if (value = 3) {
        //         console.log('找到了改元素');
        //         return true
        //     }
        //     console.log('ok');
        // })
        // console.log(newArr);

        // some 判断是否有符合条件的元素，找到第一个就退出循环
        // const arr = [1, 3, 42, '伞兵,', '卢本伟']
        // let bl = arr.some(function(value, index) {
        //     // return value.constructor == Number
        //     return typeof(value) == 'number'
        // })
        // console.log(bl);

        // map 变换数组并将返回值形成新的数组
        // const arr = [1, 3, 5, 9, 12]
        // let newArr = arr.map(x => x * 2);
        // let arr1 = arr.map(function square(value) {
        //     return value * value
        // })
        // console.log(newArr);
        // console.log(arr1);

        // every 判断是否所有的元素都符合条件
        // const arr = [2, 3, 4, 11, 21, 23]
        // let arr1 = arr.every(function(value, index) {
        //     return value > 1
        // })
        // console.log(arr1);
        // console.log(arr.every(x => x > 1));


        /*ES5新增方法-字符串方法 */
        // trim() 去除字符串两端的空格
        // let str = '    andy    ';
        // console.log(str);
        // let newStr = str.trim();
        // console.log(newStr);


        /* ES5新增方法-对象方法 */
        // const obj = {
        //     id: 1,
        //     name: '小米',
        //     price: 1999
        // };
        // Object.defineProperty(obj, 'num', {
        //         value: 1000, //添加新的属性
        //         enumerable: true
        //     })
        //     // console.log(obj);
        // Object.defineProperty(obj, 'name', {
        //     value: '华为', //更改原来的属性
        //     // enumerable: false
        // })

        // Object.defineProperty(obj, 'id', {
        //     writable: false //设置id不可重写，id作为唯一标识具有重要意义，这样就不能再更改id的值了
        // })
        // obj.id = 2;
        // Object.defineProperty(obj, 'address', {
        //     value: '卢本伟广场',
        //     enumerable: false, //设置该属性不可被遍历
        //     writable: false,
        //     configurable: false //不允许删除这个属性，也不允许修改这个属性的特性
        // });
        // // delete obj.address
        // // Object.defineProperty(obj, 'address', {
        // //     writable: true,
        // //     enumerable: true,
        // //     configurable: true
        // // });
        // console.log(obj);
        // console.log(Object.keys(obj));
        // console.log(Object.values(obj));


        /* 构造函数创建函数 */
        // const fn = new Function('a', 'b', 'console.log(a + b)') //可知所有的函数都是Function的实例
        // fn(1, 2);
        // console.dir(fn);
        // console.log(fn instanceof Object);


        /* 函数调用方式和this指向 */
        // 1.普通函数 this指向window
        // function fn() {
        //     console.log('伞兵一号卢本伟准备就绪');
        // }
        // fn();
        // fn.call();

        // 2.对象的方法 this指向该对象
        // const o = {
        //     Say: function() {
        //         console.log('人生巅峰' + this);
        //     }
        // };
        // o.Say();

        // 3.构造函数 this指向实例对象 原型对象上的this也指向实例对象
        // function Star() {};
        // Star.prototype.sing = function() {};
        // let ldh = new Star();

        // // 4.绑定事件函数 指向函数的调用者，即btn这个按钮对象
        // btn.onclick = function() {}; //点击按钮调用该函数

        // // 5.定时器函数 this指向window
        // setInterval(() => {
        //     console.log('伞兵');
        // }, 1000); //每隔1000ms调用一次该函数

        // 立即执行函数 自动调用 this指向window
        // (function() {
        //     console.log('自信即巅峰');
        // })()


        /* call */
        // const o = function(a, b) {
        //     console.log('伞兵');
        // };

        // function fn(a, b) {
        //     o.call(this);
        //     console.log(this);
        //     console.log(a + b);
        // };
        // fn.call(o, 1, 2); //call可以调用函数，可以改变函数内部this指向

        // // call的主要作用可以实现继承
        // function Father(name, age, sex) {
        //     this.name = name;
        //     this.age = age;
        //     this.sex = sex
        // };

        // function Son(name, age, sex) {
        //     Father.call(this, name, age, sex) //调用父构造函数的同时把this指向子构造函数，这样就能在子构造函数中添加父构造函数的属性和方法
        // };
        // const son = new Son('刘德华', 18, '男');
        // console.log(son.name);
        // console.log(son.age);
        // console.log(son.sex);


        /* apply */
        // apply()方法调用一个函数。简单理解为调用函数的方式，它也能改变函数的this指向
        // const o = function() {
        //     console.log('伞兵');
        // };

        // function fn(arr) {
        //     console.log(this);
        //     console.log(arr);
        // };
        // fn.apply(o, [1, 2, 3]); //传递的是数组，但是打印的是字符串
        // // apply的主要应用 可以借助Math内置对象对数组进行数学操作
        // const arr = [2, 6, 24, 44, 23];
        // let max = Math.max.apply(Math, arr);
        // let min = Math.min.apply(Math, arr);
        // console.log(max);
        // console.log(min);


        /* bind */
        // 不会调用原函数 可以改变原来函数内部的this 返回值是原函数改变this之后产生的新函数
        // const o = function() {
        //     console.log('卢本伟');
        // };

        // function fn(a, b) {
        //     o.call(this);
        //     console.log(this);
        //     console.log(a + b);
        // };
        // let f = fn.bind(o, 1, 2);
        // f()
        // fn.bind(o, 1, 2)();
        // bind函数应用


        /* 闭包 */
        // 闭包可以实现fn外面的作用域访问fn内部的局部变量。
        // function fn() {
        //     var num = 10;

        //     // function fun() {
        //     //     console.log(num);
        //     // };
        //     return function() {
        //         console.log(num);
        //     };
        // }
        // var f = fn(); //f接收了fn函数的返回值，也就是fun
        // f();
    </script>
</body>

</html>